#ifndef ESTRATEGIAMOVIMIENTOPACMAN_H
#define ESTRATEGIAMOVIMIENTOPACMAN_H

#include "EstrategiaMovimiento.h"
#include "EscenarioModelo.h"
#include "Direccion.h"
#include "Punto.h"

class EstrategiaMovimientoPacman : public EstrategiaMovimiento{
    private:

        Direccion* direccion;
		Direccion* siguienteDireccion;

		int maxAnchoSendero ;
		int maxAltoSendero ;

		bool estoyAlBorde(Punto* otroPunto){
			return otroPunto && (otroPunto->getY() == 0 || otroPunto->getY() == maxAltoSendero || otroPunto->getX() == 0 || otroPunto->getX() == maxAnchoSendero ) ;
		}
	public:

        EstrategiaMovimientoPacman(unsigned short velocidad) : EstrategiaMovimiento(velocidad){
			this->direccion = 0 ;
			this->siguienteDireccion = 0;

			int anchoGrilla = Escenario::getInstance()->getGrilla()->getColumnas();	
			int altoGrilla = Escenario::getInstance()->getGrilla()->getFilas();
			maxAnchoSendero = (anchoGrilla * EscenarioModelo::getEscenario()->getSendero()->getFactorMapeo()) - 1;
			maxAltoSendero = (altoGrilla * EscenarioModelo::getEscenario()->getSendero()->getFactorMapeo()) - 1;
		}

		virtual Punto* moverVirtual(Punto* punto){
            
			
			Punto* otroPunto = new Punto(punto);
			if(!this->direccion && !this->siguienteDireccion)
				return otroPunto;

			Direccion* direccionAplicada = 0;

			if(!this->siguienteDireccion){

				direccionAplicada = this->direccion ;
			}else{
				direccionAplicada = this->siguienteDireccion ;
			
			}

		    if(direccionAplicada->esDerecha()){
				otroPunto->incrementarX();
			}else if(direccionAplicada->esIzquierda()){
				otroPunto->decrementarX();
		   	}else if(direccionAplicada->esArriba()){
				otroPunto->decrementarY();
		    }else if(direccionAplicada->esAbajo()){
		    	otroPunto->incrementarY();
		    }

			
			if( EscenarioModelo::getEscenario()->perteneceAlSendero(otroPunto)){
				if(this->direccion)
					delete this->direccion ;
				
				this->direccion = new Direccion(this->siguienteDireccion->getValor());

				return otroPunto;
			}else{
				// Si aplique la siguienteDireccion y no funciono mantengo la actual
				if(direccionAplicada == this->siguienteDireccion && this->direccion && !this->estoyAlBorde(otroPunto)){
					delete otroPunto;
					Punto* unPunto = new Punto(punto);

					if(this->direccion->esDerecha()){
						unPunto->incrementarX();
					}else if(this->direccion->esIzquierda()){
						unPunto->decrementarX();
					}else if(this->direccion->esArriba()){
						unPunto->decrementarY();
					}else if(this->direccion->esAbajo()){
						unPunto->incrementarY();
					}
					if( EscenarioModelo::getEscenario()->perteneceAlSendero(unPunto)){
						return unPunto;
					}else{
						delete unPunto;
					}

			    // Si estoy al borde, osea el punto al que quiero ir esta afuera del sendero -> teletransporto
				}else if(this->estoyAlBorde(otroPunto) ){
					if(otroPunto->getX() == maxAnchoSendero){
						otroPunto->setX(1);
					}else if (otroPunto->getX() == 0){
						otroPunto->setX(maxAnchoSendero - 1 );
					}else if (otroPunto->getY() == maxAltoSendero){
						otroPunto->setY(1);
					}else if (otroPunto->getY() == 0){
						otroPunto->setY(maxAltoSendero - 1 );
					}

					return otroPunto;
				}else{
					delete otroPunto;
				}
			}

			// Si no pertenece al sendero retorno un punto nuevo con las mismas coordenadas
			// Me va a permitir liberar el puntero anterior.
			return new Punto(punto); 
		}
		
		~EstrategiaMovimientoPacman(){
			delete this->direccion ;
		
		}

        void setDireccion(Direccion* unaDireccion){
				
				/*if(this->direccion)
					delete this->direccion;
				this->direccion = unaDireccion;*/
				if(this->siguienteDireccion)
					delete this->siguienteDireccion;
				this->siguienteDireccion = unaDireccion ;
        }

		Direccion* getDireccion(){
			return this->direccion ;
		}

		unsigned short getVelocidad(){
			return this->velocidad;
		}
};

#endif